/*
   Copyright 2011 James Bowling

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package com.armedia.dctm.constraints.integration.test;

import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;

import com.armedia.dctm.constraints.Constraint;
import com.armedia.dctm.constraints.NotNullConstraintException;
import com.armedia.dctm.constraints.NotNullConstraintImpl;
import com.armedia.dctm.constraints.test.AbstractTestCase;
import com.documentum.com.DfClientX;
import com.documentum.com.IDfClientX;
import com.documentum.fc.client.IDfCollection;
import com.documentum.fc.client.IDfPersistentObject;
import com.documentum.fc.client.IDfQuery;
import com.documentum.fc.client.IDfType;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.IDfAttr;
import com.documentum.fc.common.IDfValue;

public class NotNullConstraintImplTestCase extends AbstractTestCase {
	
	private static final String TEST_TYPE = "test_constraints_notnull";
	
	String[] attrTypes = { "string", "ID", "time" };
	
	boolean[] repeatingAttr = { false, true };	
			
	@Before
	public void setUp() throws Exception {
		super.setTransactional(false);
		super.setUp();		
	}
	
	@Override
	public void tearDown() throws Exception {
		super.tearDown();
	}	
	
	@Test
	public void testCheckWithViolation() throws DfException {
		for (String attrType : attrTypes) {
			for (boolean repeating : repeatingAttr) {
				createTestType();				
				alterTypeForTest(attrType, repeating);
				final IDfPersistentObject newObject = session.newObject(TEST_TYPE);
				boolean exceptionThrown = false;
				try {
					String attrName = getAttributeName(attrType, repeating);
					Constraint notNullConstraint = new NotNullConstraintImpl(TEST_TYPE, attrName);
					if (repeating) {
						final int attrIndex = getAttrIndex(newObject.getType(), attrName);
						final IDfAttr attr = newObject.getAttr(attrIndex);
						int attrDataType = attr.getDataType();
						switch (attrDataType) {
						case IDfValue.DF_STRING:
							newObject.setRepeatingString(attrName, 0, null);
							break;
						case IDfValue.DF_ID:
							newObject.setRepeatingId(attrName, 0, null);
							break;
						case IDfValue.DF_TIME:
							newObject.setRepeatingTime(attrName, 0, null);
							break;							
						default:
							break;
						}
					}
					notNullConstraint.check(newObject);
				} catch (NotNullConstraintException e) {
					exceptionThrown = true;
				}
				final String msg = String.format("A %s should have been thrown.", NotNullConstraintException.class.getSimpleName());
				assertTrue(msg, exceptionThrown);
				dropTestType();							
			}
		}
	}
	
/*	@Test
	public void testCheckWithoutViolation() throws DfException {
		for (String attrType : attrTypes) {
			for (boolean repeating : repeatingAttr) {
				createTestType();				
				final IDfPersistentObject newObject = session.newObject(TEST_TYPE);
				String attrName = getAttributeName(attrType, repeating);
				Constraint notNullConstraint = new NotNullConstraintImpl(TEST_TYPE, attrName);
				if (repeating) {
					newObject.setString(attrName, "test");
				} else {
					newObject.setRepeatingString(attrName, 0, "test");
				}
				notNullConstraint.check(newObject);
				dropTestType();	
			}
		}
	}*/
	
	private void alterTypeForTest(final String attributeType, final boolean repeating) throws DfException {
		String attrName = getAttributeName(attributeType, repeating);
		String alterTypePattern = "alter type %s add %s %s %s (SET \"label_text\"='%s', NOT NULL)";
		String typeDef = attributeType.equals("string") ? "string(255)" : attributeType;
		String repeatingToken = repeating ? "repeating" : "";
		final String alterTypeDql = String.format(alterTypePattern, TEST_TYPE, attrName, typeDef, repeatingToken, attrName);
		IDfClientX client = new DfClientX();
		IDfQuery q = client.getQuery();
		q.setDQL(alterTypeDql);
		IDfCollection coll = null;
		try {
			coll = q.execute(session, IDfQuery.READ_QUERY);		
		} finally {
			if (coll != null) {
				coll.close();
				coll = null;
			}
		}		
	}

	private String getAttributeName(String attributeType, boolean repeating) {
		final String singleOrRepeating = !repeating ? "single": "repeating";
		String attrName = String.format("%s_%s", singleOrRepeating, attributeType.toLowerCase());
		return attrName;
	}
	
	private void dropTestType() throws DfException {
		String dropTypeDql = "drop type %s";
		final String alterTypeDql = String.format(dropTypeDql, TEST_TYPE);
		IDfClientX client = new DfClientX();
		IDfQuery q = client.getQuery();
		q.setDQL(alterTypeDql);
		IDfCollection coll = null;
		try {
			coll = q.execute(session, IDfQuery.READ_QUERY);		
		} finally {
			if (coll != null) {
				coll.close();
				coll = null;
			}
		}		
	}
	
	private void createTestType() throws DfException {
		String createTypePattern = "create type %s ( dummy_attr string(255) ) with supertype null publish";
		final String createTypeDql = String.format(createTypePattern, TEST_TYPE);
		IDfClientX client = new DfClientX();
		IDfQuery q = client.getQuery();
		q.setDQL(createTypeDql);
		IDfCollection coll = null;
		try {
			coll = q.execute(session, IDfQuery.READ_QUERY);		
		} finally {
			if (coll != null) {
				coll.close();
				coll = null;
			}
		}		
	}
	
	private int getAttrIndex(final IDfType type, String attributeName) throws DfException {
		// final int attrIndex = type.findAttrIndex(this.attributeName); <- this should work, but it doesn't 		
		int attrIndex = -1;
		for (int i = 0; i < type.getTypeAttrCount(); i++) {
			final String name = type.getTypeAttr(i).getName();
			if (name.equals(attributeName)) {
				attrIndex = i;
				break;
			}
		}
		return attrIndex;
	}	

}
